const express = require('express') // 导入 express
const helmet = require('helmet') // 安全HTTP头
const cors = require('cors') // CORS跨域控制
const rateLimit = require('express-rate-limit') // 请求限速
const joi = require('joi') // 参数验证
const connectDB = require('./config/db') // 数据库连接
const userRoutes = require('./routes/userRoutes') // 用户路由
const bookRouter = require('./routes/bookRoutes') // 书籍路由

// 创建服务器的实例对象
const app = express()

// 跨域资源共享设置
app.use(cors())

// 安全HTTP头设置（防止XSS、点击劫持等）
app.use(helmet())

// 请求体大小限制（防止DoS攻击）
app.use(express.json({ limit: '100kb' }))

// 配置解析表单数据的中间件，注意：这个中间件，只能解析 application/x-www-form-urlencoded 格式的表单数据
app.use(express.urlencoded({ extended: false }))

// API请求限速（防止暴力攻击）
const limiter = rateLimit({
	windowMs: 10 * 60 * 1000, // 10分钟
	max: 100, // 每个IP最多100次请求
	message: '请求过于频繁，请稍后再试'
})
app.use(limiter)

// 一定要在路由之前，封装 res.cc 函数
app.use((req, res, next) => {
	// status 默认值为 1，表示失败的情况
	// err 的值，可能是一个错误对象，也可能是一个错误的描述字符串
	res.cc = function (err, status = 1) {
		res.send({
			status,
			message: err instanceof Error ? err.message : err
		})
	}
	next()
})

// 用户路由
app.use('/api', userRoutes)
// 书籍路由
app.use('/api/books', bookRouter)
// 托管静态资源文件
app.use('/uploads', express.static('./uploads'))

// 定义错误级别的中间件
app.use((err, req, res, next) => {
	// 验证失败导致的错误
	if (err instanceof joi.ValidationError) return res.cc(err)
	// 身份认证失败后的错误
	if (err.name === 'UnauthorizedError') return res.cc('身份认证失败！')
	// 未知的错误
	res.cc(err)
})

// 连接数据库
connectDB()

// 启动服务器
const PORT = process.env.PORT || 5000
app.listen(PORT, () => {
	console.log(`✅ api server running at http://127.0.0.1:${PORT}`)
})
